package com.changgou.consume.listener;

import com.alibaba.fastjson.JSON;
import com.changgou.consume.config.RabbitMQConfig;
import com.changgou.consume.service.SeckillOrderService;
import com.changgou.seckill.pojo.SeckillOrder;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.mysql.cj.x.protobuf.MysqlxDatatypes;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * 保存秒杀订单到数据库, 扣减秒杀商品库存到数据库监听器
 */
@Component
public class SaveSeckillOrderListener {

    @Autowired
    private SeckillOrderService seckillOrderService;

    /**
     * 由于队列使用代码创建, 所以@RabbitListener注解写在方法上
     * @param channel   通道, 为了获取传递数据的通道号, 从队列中发送接收数据, 通道号是唯一的
     * @param message   消息对象, 从这里面可以接收到队列发过来的消息数据
     */
    @RabbitListener(queues = RabbitMQConfig.SECKILL_ORDER)
    public void messageHandler(Channel channel, Message message) {
        try {
            //控制接收rabbitMq中数据的并发量, 300个并发, 可以加快mysql保存数据的效率, mysql又不至于宕机
            channel.basicQos(300);

            /**
             * 1. 将消息转换为秒杀订单对象
             */
            //获取消息体
            byte[] body = message.getBody();
            //将消息体转换成字符串类型, 也就是获取秒杀订单json格式字符串
            String seckillOrderJsonStr = new String(body);

            //将json格式字符串转换成对象
            SeckillOrder seckillOrder = JSON.parseObject(seckillOrderJsonStr, SeckillOrder.class);

            //2. 同步mysql数据, 存储订单信息, 扣减秒杀商品库存
            Boolean flag = seckillOrderService.saveSeckillOrder(seckillOrder);

            //3. 如果更新数据库操作成功, 消费者发起成功通知
            if (flag) {
                /**
                 * 更新数据库操作成功
                 * 消费者发起成功通知
                 * DeliveryTag: 消息的唯一标识  channel+消息编号
                 * 第二个参数：是否开启批量处理 false:不开启批量
                 */
                try {
                    channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            //4. 更新数据库操作失败, 消费者发起失败通知
            /**
             * 返回失败通知
             * 第一个boolean true所有消费者都会拒绝这个消息，false代表只有当前消费者拒绝
             * 第二个boolean true当前消息会进入到死信队列，false重新回到原有队列中，默认回到头部
             */
            try {
                channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }


    }
}
